package com.warm.knowledge.algorithm.structure.tree_bst;


import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

/**
 * @Date: 2019/12/3 11:59
 * @Author: LChuang
 * @Description: Binary Search Tree (二叉搜索树)
 */
public class BST<E extends Comparable<E>> {

    private class Node{
        public E e;
        public Node left, right;

        public Node(E e){
            this.e = e;
            left = null;
            right = null;
        }
    }

    private Node root;
    private int size;

    public BST(){
        root = null;
        size = 0;
    }

    public int getSize(){
        return size;
    }

    public boolean isEmpty(){
        return size == 0;
    }

    public void add(E e){
        root = add(root, e);
    }

    /**
     * 以 node 为根的二分搜索树中插入元素e, 递归算法
     * 返回插入新节点后二分搜索树的根
     * @param node
     * @param e
     */
    private Node add(Node node, E e){
        if(node == null){
            size++;
            return new Node(e);
        }

        /**
         * compareTo
         *   如果参数字符串等于此字符串，则返回值 0
         *   如果此字符串小于字符串参数，则返回一个小于 0 的值
         *   如果此字符串大于字符串参数，则返回一个大于 0 的值
         */
        if(e.compareTo(node.e) < 0){
            node.left = add(node.left, e);
        }else if(e.compareTo(node.e) > 0){
            node.right = add(node.right, e);
        }

        return node;
    }

    public boolean contains(E e){
        return contains(root, e);
    }

    /**
     * 以 node 为根的二分搜索树中是否包含元素e
     * @param node
     * @param e
     * @return
     */
    private boolean contains(Node node, E e){
        if(node == null){
            return false;
        }

        if(e.compareTo(node.e) == 0){
            return true;
        }else if(e.compareTo(node.e) == 0){
            return contains(node.left, e);
        }else {
            return contains(node.right, e);
        }
    }

    public void preOrder(){
        preOrder(root);
    }

    /**
     * 以 node 为根的, 递归算法 前序遍历: 根 -> 左 -> 右
     * @param node
     */
    private void preOrder(Node node){
        if(node == null){
            return;
        }

        System.out.println(node.e);
        preOrder(node.left);
        preOrder(node.right);
    }

    public void inOrder(){
        inOrder(root);
    }

    /**
     * 以node为根的二分搜索树, 递归算法 中序遍历: 左-> 根-> 右
     * @param node
     */
    private void inOrder(Node node){
        if(node == null){
            return;
        }

        inOrder(node.left);
        System.out.println(node.e);
        inOrder(node.right);
    }

    public void postOrder(){
        postOrder(root);
    }

    /**
     *  以node为根的二分搜索树, 递归算法 后序遍历:  左-> 右-> 根
     */
    private void postOrder(Node node){
        if(node == null){
            return;
        }

        postOrder(node.left);
        postOrder(node.right);
        System.out.println(node.e);
    }

    /**
     * 非递归前序遍历
     */
    public void preOrderNR(){
        Stack<Node> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()){
            Node cur = stack.pop();
            System.out.println(cur.e);

            if(cur.right != null){
                stack.push(cur.right);
            }
            if(cur.left != null){
                stack.push(cur.left);
            }
        }
    }

    /**
     * 层序遍历
     */
    public void levelOrder(){
        Queue<Node> q = new LinkedList<>();
        q.add(root);
        while (!q.isEmpty()){
            Node cur = q.remove();
            System.out.println(cur.e);

            if(cur.left != null){
                q.add(cur.left);
            }
            if(cur.right != null){
                q.add(cur.right);
            }
        }
    }

    public E minimum(){
        if(size == 0){
            throw new IllegalArgumentException("BST is empty");
        }
        Node minNode = minimum(root);
        return minNode.e;
    }

    /**
     * 以node为根的二分搜索树的最小值所在的节点
     * @param node
     * @return
     */
    private Node minimum(Node node){
        if(node.left == null){
            return node;
        }
        return minimum(node.left);
    }

    public E maximum(){
        if(size == 0){
            throw new IllegalArgumentException("BST is empty");
        }
        Node maxNode = maximum(root);
        return maxNode.e;
    }

    public E removeMin(){
        E ret = minimum();
        root = removeMin(root);
        return ret;
    }

    /**
     * 删除掉以node为根的二分搜索树中的最小节点
     * 返回删除节点后新的二分搜索树的根
     * @param node
     * @return
     */
    private Node removeMin(Node node){
        if(node.left == null){
            Node rightNode = node.right;
            node.right = null;
            size--;
            return rightNode;
        }

        node.left = removeMin(node.left);
        return node;
    }

    public E removeMax(){
        E ret = maximum();
        root = removeMax(root);
        return ret;
    }

    /**
     * 删除掉以node为根的二分搜索树中的最大节点
     * 返回删除节点后新的二分搜索树的根
     * @param node
     * @return
     */
    private Node removeMax(Node node){

        if(node.right == null){
            Node leftNode = node.left;
            node.left = null;
            size --;
            return leftNode;
        }

        node.right = removeMax(node.right);
        return node;
    }

    /**
     * 返回以node为根的二分搜索树的最大值所在的节点
     * @param node
     * @return
     */
    private Node maximum(Node node){
        if( node.right == null ){
            return node;
        }

        return maximum(node.right);
    }

    public void remove(E e){
        root = remove(root, e);
    }

    Node remove(Node node, E e){
        if(node == null){
            return null;
        }

        if(e.compareTo(node.e) < 0){
            node.left = remove(node.left, e);
            return node;
        }else if(e.compareTo(node.e) > 0){
            node.right = remove(node.right, e);
            return node;
        }else {
            //待删除节点左子树为空的情况
            if(node.left == null){
                Node rightNode = node.right;
                node.right = null;
                size--;
                return rightNode;
            }

            //待删除节点右子数为空的情况
            if(node.right == null){
                Node leftNode = node.left;
                node.left = null;
                size--;
                return leftNode;
            }

            //待删除节点左右子数均不为空的情况
            //找到比待删除节点大的最小节点, 待删除节点右子树的最小节点
            //用这个节点顶替待删除节点位置
            Node successor = new Node(minimum(node.right).e);
            size++;

            successor.right = removeMin(node.right);
            successor.left = node.left;

            node.left = node.right = null;
            size--;

            return successor;
        }
    }

    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
        genBSTString(root, 0, res);
        return res.toString();
    }

    /**
     * 以node为根节点, 深度为depth的描述二叉树的字符串
     * @param node
     * @param depth
     * @param res
     */
    private void genBSTString(Node node, int depth, StringBuilder res){
        if(node == null){
            res.append(genDepthString(depth) + "null\n");
            return;
        }

        res.append(genDepthString(depth) + node.e + "\n");
        genBSTString(node.left, depth + 1, res);
        genBSTString(node.right, depth + 1, res);
    }

    private String genDepthString(int depth){
        StringBuilder res = new StringBuilder();
        for (int i = 0; i < depth; i++){
            res.append("--");
        }
        return res.toString();
    }
}
